using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using RestSharp;
using System.Net;

namespace PmSoft.Core.Http;

/// <summary>
/// RestSharp 实现的 HTTP 客户端，封装了 RestSharp 库的 HTTP 请求逻辑
/// </summary>
public class RestSharpHttpClient : IHttpClient
{
	private RestClient _client;  // RestSharp 客户端实例
	private readonly ILogger<RestSharpHttpClient> _logger;  // 日志记录器
	private readonly JsonSerializerSettings _jsonSettings;  // JSON 序列化设置

	/// <summary>
	/// 构造函数，初始化 RestSharp 客户端和默认设置
	/// </summary>
	public RestSharpHttpClient(ILogger<RestSharpHttpClient> logger, JsonSerializerSettings? jsonSettings = null)
	{
		// 初始化 RestSharp 客户端，默认超时时间设置为5分钟
		_client = new RestClient(new RestClientOptions
		{
			ThrowOnAnyError = true,
			Timeout = TimeSpan.FromMinutes(5)
		});
		_logger = logger;
		_jsonSettings = jsonSettings ?? new JsonSerializerSettings
		{
			DateFormatString = "yyyy-MM-dd HH:mm:ss",
			NullValueHandling = NullValueHandling.Ignore
		};
	}

	/// <summary>
	/// 设置请求的超时时间
	/// </summary>
	public IHttpClient WithTimeout(int timeout)
	{
		var options = new RestClientOptions
		{
			ThrowOnAnyError = _client.Options.ThrowOnAnyError,
			Timeout = TimeSpan.FromMinutes(timeout)
		};

		// 复制现有请求头
		var headers = _client.DefaultParameters
			.Where(p => p.Type == ParameterType.HttpHeader)
			.ToDictionary(p => p.Name ?? string.Empty, p => p.Value?.ToString() ?? string.Empty);

		_client = new RestClient(options);

		// 恢复之前的请求头
		foreach (var (key, value) in headers)
		{
			_client.AddDefaultHeader(key, value);
		}

		return this;
	}

	/// <summary>
	/// 设置单个请求头
	/// </summary>
	public IHttpClient WithHeader(string name, string value)
	{
		_client.AddDefaultHeader(name, value);
		return this;
	}

	/// <summary>
	/// 设置多个请求头
	/// </summary>
	public IHttpClient WithHeaders(IDictionary<string, string> headers)
	{
		foreach (var header in headers)
		{
			_client.AddDefaultHeader(header.Key, header.Value);
		}
		return this;
	}

	/// <summary>
	/// 设置 User-Agent 请求头
	/// </summary>
	public IHttpClient WithUserAgent(string userAgent)
	{
		_client.AddDefaultHeader("User-Agent", userAgent);
		return this;
	}

	/// <summary>
	/// 设置 Bearer Token 认证
	/// </summary>
	public IHttpClient WithBearerToken(string token)
	{
		_client.AddDefaultHeader("Authorization", $"Bearer {token}");
		return this;
	}

	/// <summary>
	/// 发送 GET 请求并返回指定类型的对象
	/// </summary>
	public T Get<T>(string url, object? queryParams = null)
	{
		return GetAsync<T>(url, queryParams).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步发送 GET 请求并返回指定类型的对象
	/// </summary>
	public async Task<T> GetAsync<T>(string url, object? queryParams = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url);
			if (queryParams != null)
			{
				request.AddObject(queryParams);  // 将查询参数添加到请求
			}

			var response = await _client.ExecuteAsync(request, cancellationToken);  // 发送请求并获取响应
			HandleResponse(response);  // 处理响应

			return Json.Parse<T>(response.Content, _jsonSettings)
				?? throw new HttpRequestException("响应内容为空");
		}
		catch (Exception ex)
		{
			HandleException(ex, url);  // 处理异常
			throw;
		}
	}

	/// <summary>
	/// 发送 GET 请求并返回字符串
	/// </summary>
	public string GetString(string url, object? queryParams = null)
	{
		return GetStringAsync(url, queryParams).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步发送 GET 请求并返回字符串
	/// </summary>
	public async Task<string> GetStringAsync(string url, object? queryParams = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url);
			if (queryParams != null)
			{
				request.AddObject(queryParams);
			}

			var response = await _client.ExecuteAsync(request, cancellationToken);
			HandleResponse(response);  // 处理响应
			return response.Content ?? string.Empty;
		}
		catch (Exception ex)
		{
			HandleException(ex, url);  // 处理异常
			throw;
		}
	}

	/// <summary>
	/// 发送 POST 请求并返回指定类型的对象
	/// </summary>
	public T Post<T>(string url, object? data = null)
	{
		return PostAsync<T>(url, data).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步发送 POST 请求并返回指定类型的对象
	/// </summary>
	public async Task<T> PostAsync<T>(string url, object? data = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url, Method.Post);
			if (data != null)
			{
				request.AddJsonBody(data);  // 将请求数据添加到请求体
			}

			var response = await _client.ExecuteAsync(request, cancellationToken);
			HandleResponse(response);  // 处理响应

			return Json.Parse<T>(response.Content, _jsonSettings)
				?? throw new HttpRequestException("响应内容为空");
		}
		catch (Exception ex)
		{
			HandleException(ex, url);  // 处理异常
			throw;
		}
	}

	/// <summary>
	/// 发送 POST 请求并返回字符串
	/// </summary>
	public string PostString(string url, object? data = null)
	{
		return PostStringAsync(url, data).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步发送 POST 请求并返回字符串
	/// </summary>
	public async Task<string> PostStringAsync(string url, object? data = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url, Method.Post);
			if (data != null)
			{
				request.AddJsonBody(data);
			}

			var response = await _client.ExecuteAsync(request, cancellationToken);
			HandleResponse(response);  // 处理响应
			return response.Content ?? string.Empty;
		}
		catch (Exception ex)
		{
			HandleException(ex, url);  // 处理异常
			throw;
		}
	}

	/// <summary>
	/// 上传单个文件并返回指定类型的对象
	/// </summary>
	public T UploadFile<T>(string url, string filePath, string fileParameterName = "file", IDictionary<string, string>? additionalData = null)
	{
		return UploadFileAsync<T>(url, filePath, fileParameterName, additionalData).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步上传单个文件并返回指定类型的对象
	/// </summary>
	public async Task<T> UploadFileAsync<T>(string url, string filePath, string fileParameterName = "file", IDictionary<string, string>? additionalData = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url, Method.Post);
			request.AddFile(fileParameterName, filePath);  // 添加文件到请求

			// 添加额外数据（如果有）
			if (additionalData != null)
			{
				foreach (var (key, value) in additionalData)
				{
					request.AddParameter(key, value);
				}
			}

			var response = await _client.ExecuteAsync(request, cancellationToken);
			HandleResponse(response);  // 处理响应

			return Json.Parse<T>(response.Content, _jsonSettings)
				?? throw new HttpRequestException("响应内容为空");
		}
		catch (Exception ex)
		{
			HandleException(ex, url);  // 处理异常
			throw;
		}
	}

	/// <summary>
	/// 上传多个文件并返回指定类型的对象
	/// </summary>
	public T UploadFiles<T>(string url, IEnumerable<string> filePaths, string fileParameterName = "files", IDictionary<string, string>? additionalData = null)
	{
		return UploadFilesAsync<T>(url, filePaths, fileParameterName, additionalData).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步上传多个文件并返回指定类型的对象
	/// </summary>
	public async Task<T> UploadFilesAsync<T>(string url, IEnumerable<string> filePaths, string fileParameterName = "files", IDictionary<string, string>? additionalData = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url, Method.Post);

			// 添加多个文件到请求
			foreach (var filePath in filePaths)
			{
				if (!File.Exists(filePath))
				{
					throw new FileNotFoundException($"文件不存在: {filePath}");
				}
				request.AddFile(fileParameterName, filePath);
			}

			// 添加额外数据（如果有）
			if (additionalData != null)
			{
				foreach (var (key, value) in additionalData)
				{
					request.AddParameter(key, value);
				}
			}

			var response = await _client.ExecuteAsync(request, cancellationToken);
			HandleResponse(response);  // 处理响应

			return Json.Parse<T>(response.Content, _jsonSettings)
				?? throw new HttpRequestException("响应内容为空");
		}
		catch (Exception ex)
		{
			HandleException(ex, url);  // 处理异常
			throw;
		}
	}

	/// <summary>
	/// 处理 HTTP 响应，检查是否成功
	/// </summary>
	private void HandleResponse(RestResponse response)
	{
		if (!response.IsSuccessful)
		{
			var statusCode = response.StatusCode;
			var errorMessage = response.ErrorMessage ?? "未知错误";

			switch (statusCode)
			{
				case HttpStatusCode.NotFound:
					throw new HttpRequestException($"请求的资源不存在: {errorMessage}");
				case HttpStatusCode.Unauthorized:
					throw new HttpRequestException("未授权的请求");
				case HttpStatusCode.Forbidden:
					throw new HttpRequestException("禁止访问该资源");
				case HttpStatusCode.RequestTimeout:
					throw new HttpRequestException("请求超时");
				case HttpStatusCode.BadRequest:
					throw new HttpRequestException($"无效的请求: {errorMessage}");
				case HttpStatusCode.InternalServerError:
					throw new HttpRequestException($"服务器内部错误: {errorMessage}");
				case HttpStatusCode.BadGateway:
					throw new HttpRequestException("网关错误");
				case HttpStatusCode.ServiceUnavailable:
					throw new HttpRequestException("服务不可用");
				case HttpStatusCode.GatewayTimeout:
					throw new HttpRequestException("网关超时");
				default:
					throw new HttpRequestException($"HTTP请求失败: {statusCode} - {errorMessage}");
			}
		}
	}

	/// <summary>
	/// 处理异常并记录日志
	/// </summary>
	private void HandleException(Exception ex, string url)
	{
		var errorMessage = ex switch
		{
			HttpRequestException httpEx => $"HTTP请求异常: {httpEx.Message}",
			TimeoutException => "请求超时",
			OperationCanceledException => "请求被取消",
			JsonSerializationException jsonEx => $"JSON序列化错误: {jsonEx.Message}",
			FileNotFoundException fileEx => $"文件不存在: {fileEx.Message}",
			UnauthorizedAccessException => "没有足够的权限访问文件",
			IOException ioEx => $"IO操作错误: {ioEx.Message}",
			InvalidOperationException invEx => $"无效的操作: {invEx.Message}",
			_ => $"请求发生异常: {ex.Message}"
		};

		_logger.LogError(ex, "请求 {Url} 失败: {ErrorMessage}", url, errorMessage);
	}

	/// <summary>
	/// 下载文件并保存到指定路径
	/// </summary>
	public void DownloadFile(string url, string saveFilePath)
	{
		DownloadFileAsync(url, saveFilePath).GetAwaiter().GetResult();
	}

	/// <summary>
	/// 异步下载文件并保存到指定路径
	/// </summary>
	public async Task DownloadFileAsync(string url, string saveFilePath, IProgress<double>? progress = null, CancellationToken cancellationToken = default)
	{
		try
		{
			var request = new RestRequest(url);
			var response = await _client.DownloadStreamAsync(request, cancellationToken);

			if (response == null)
			{
				throw new HttpRequestException("下载失败：响应流为空");
			}

			var fileInfo = new FileInfo(saveFilePath);
			fileInfo.Directory?.Create();  // 确保目录存在

			using var fileStream = File.Create(saveFilePath);  // 创建文件流
			var buffer = new byte[81920];  // 缓冲区
			var totalBytesRead = 0L;
			var contentLength = response.Length;

			// 下载文件并写入到文件流
			while (true)
			{
				var bytesRead = await response.ReadAsync(buffer, cancellationToken);
				if (bytesRead == 0) break;

				await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken);
				totalBytesRead += bytesRead;

				// 进度报告
				if (progress != null && contentLength > 0)
				{
					var progressPercentage = (double)totalBytesRead / contentLength * 100;
					progress.Report(Math.Min(progressPercentage, 100));
				}
			}
		}
		catch (Exception ex)
		{
			HandleDownloadException(ex, url, saveFilePath);  // 处理下载异常
			throw;
		}
	}

	/// <summary>
	/// 处理下载异常并记录日志
	/// </summary>
	private void HandleDownloadException(Exception ex, string url, string saveFilePath)
	{
		var errorMessage = ex switch
		{
			HttpRequestException httpEx => $"下载失败: {httpEx.Message}",
			UnauthorizedAccessException => "没有权限写入文件",
			DirectoryNotFoundException => "保存目录不存在",
			IOException ioEx => $"文件IO错误: {ioEx.Message}",
			TimeoutException => "下载超时",
			OperationCanceledException => "下载已取消",
			_ => $"下载失败: {ex.Message}"
		};

		_logger.LogError(ex, "下载文件失败 - URL: {Url}, 保存路径: {SavePath}, 错误: {ErrorMessage}",
			url, saveFilePath, errorMessage);

		// 如果文件已部分下载，则删除
		if (File.Exists(saveFilePath))
		{
			try
			{
				File.Delete(saveFilePath);
			}
			catch (Exception deleteEx)
			{
				_logger.LogWarning(deleteEx, "清理未完成的下载文件失败: {SavePath}", saveFilePath);
			}
		}
	}
}
